package org.ftz.JudgeOnline.CPP;
import java.io.*;
import java.util.concurrent.*;
import org.apache.log4j.Logger;
public class ExecuteCLangService {
    private static final Logger log = Logger.getLogger(ExecuteCLangService.class);
    public static final String CODE_PATH = "D:/BigProgram/";  //代码存放路径
    private boolean generateCFile(String content){ //C代码
        BufferedWriter out = null;
        try{
            FileOutputStream fileOutputStream = new FileOutputStream(CODE_PATH + "test.cpp", false); //写入
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
            out = new BufferedWriter(outputStreamWriter);
            out.write(content);
        }catch (Exception e){
            log.error(e.getCause().getMessage());
            return false;
        }finally {
            try {
                out.close();
            }catch (IOException e){
                log.error(e.getCause().getMessage());
                return false;
            }
        }
        return true;
    }
    public String runCLangCode(String sourceCode){ //源代码
        boolean b = generateCFile(sourceCode); //先生成文件
        System.out.println(b);
        Executor executor = Executors.newSingleThreadExecutor();
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                String compileResult = execCmd("g++ "+CODE_PATH+"test.cpp "+"-o "+CODE_PATH+"test",null); //编译C文件
                System.out.println("hello");
                if (compileResult.equals("")){ //编译不出错的情况，replaceAll将\n换成HTML的换行，空格换成HTML的空格
                    System.out.println("编译成功");
                    return "编译成功!@"+execCmd("cmd /c " + CODE_PATH+"test.exe"+" < D:\\BigProgram\\1.txt",null);
                } else { //编译出错，找到error的位置，返回error及其后的信息
                    System.out.println("编译出错");
                    int errorIndex = compileResult.indexOf("error");
                    return "编译出错!@"+compileResult.substring(errorIndex);
                }
            }
        });
        executor.execute(futureTask);
        try {
            execCmd("taskkill /f /im test.exe",null); //编译运行完毕将text.exe的进程kill
            log.info("killed test.exe");
        }catch (Exception e){
            e.printStackTrace();
        }
        String result = "";
        try{
            result=futureTask.get(10, TimeUnit.SECONDS); //设置超时时间
        }catch (InterruptedException e) {
            log.info("Interrupt");
            result = "程序中断，请检查是否有内存冲突等错误";
        }catch (ExecutionException e) {
            result = "程序执行错误";
            futureTask.cancel(true);
        }catch (TimeoutException e) {
            result = "时间超限，请检查是否存在无限循环等程序无法自动结束的情况";
        }
        log.info("result - "+result);
        return result.equals("")?"没有输出":result;
    }
    private String execCmd(String cmd, File dir) throws Exception {  //执行系统命令, 返回执行结果
        StringBuilder result = new StringBuilder();
        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;
        String command = cmd; //加入输入
        try {
            process = Runtime.getRuntime().exec(command, null, dir);  // 执行命令, 返回一个子进程对象（命令在子进程中执行）
            new Thread(){ //用另一个线程输入参数
                public void run(){
                }
            };
            process.waitFor(); // 方法阻塞, 等待命令执行完成（成功会返回0）
            InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), "UTF-8"); // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出（PS: 子进程的输出就是主进程的输入）
            bufrIn = new BufferedReader(inputStreamReader);
            InputStreamReader inputStreamReader1 = new InputStreamReader(process.getErrorStream(), "UTF-8");
            bufrError = new BufferedReader(inputStreamReader1);
            String line = null; // 读取输出
            while ((line = bufrIn.readLine()) != null) {
                result.append(line).append('\n');
            }
            while ((line = bufrError.readLine()) != null) {
                result.append(line).append('\n');
            }

        } finally {
            closeStream(bufrIn);
            closeStream(bufrError);
            if (process != null) {  // 销毁子进程
                process.destroy();
            }
        }
        return result.toString(); // 返回执行结果
    }
    private void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (Exception e) {
            }
        }
    }
}
